// by Xeno

// [_observers, _cannons] spawn XfHandleObservers; 
XfHandleObservers = {
	private ["_observers","_nextaritime", "_height", "_type", "_radius", "_i", "_observer", "_enemy", "_distance", "_man_type", "_artillery_pieces", "_arty"];
	if (!isServer) exitWith {};

	_observers = _this select 0;
	_artillery_pieces = _this select 1;
	
	_enemy_ari_available = true;
	_nextaritime = 0;
	_height = 150;
	_type = "";
	_radius = 30;
	
	if (isnil "d_ai_arti_available_time") then {
		d_ai_arti_available_time = 120;
	};
	
	_man_type = switch (d_enemy_side) do {
		case "WEST": {"SoldierWB"};
		case "EAST": {"SoldierEB"};
		case "GUER": {"SoldierGB"};
	};

	sleep 10.123;
	while {count _observers > 0 && count _artillery_pieces > 0} do {
		for [{_i = 0},{_i < count _artillery_pieces},{_i = _i + 1}] do {
			_arty = _artillery_pieces select _i;
			if (!alive _arty) then { _artillery_pieces set [_i, "xXdelXx"]; }
			else { if (!canFire _arty) then { _artillery_pieces set [_i, "xXdelXx"]; };	};
		}; 
		_artillery_pieces = _artillery_pieces - ["xXdelXx"];
		//__MPCheck;
		for "_i" from 0 to 2 do {
			private "_observer";
			_observer = _observers select _i;
			if (!isNull _observer && alive _observer) then {
				if (_enemy_ari_available) then {
					_enemy = _observer findNearestEnemy _observer;
					if (!isNull _enemy && (_observer knowsAbout _enemy >= 1.5) && !((vehicle _enemy) isKindOf "Air")) then {
						_distance = _observer distance _enemy;
						if (_distance < 500) then {
							_pos_nearest = [getPosASL _enemy select 0, getPosASL _enemy select 1, 0];
							_near_targets = _pos_nearest nearObjects [_man_type, 35];
							if (count _near_targets == 0) then {
								_enemy_ari_available = false;
								_nextaritime = time + d_ai_arti_available_time + (random 120);
								[_pos_nearest,floor (random 2),_artillery_pieces] spawn XfShootArti;
							} else {
								_enemy_ari_available = false;
								_nextaritime = time + d_ai_arti_available_time + (random 120);
								if ((random 100) < 15) then {// 1 to 6 chance for smoke
									[_pos_nearest,2,_artillery_pieces] spawn XfShootArti;
								};
							};
						};
					};
				};
				sleep 2.321;
			};
		};
		sleep 5.123;
		if (time > _nextaritime && !_enemy_ari_available) then {_enemy_ari_available = true};
	};
};

// [_cannon, _target, _rounds, _delay] spawn XfFireArtilleryPiece;
XfFireArtilleryPiece = {
	private ["_gun","_target","_rounds","_newTarget","_spawnDelay","_delay","_tposx","_tposy","_tposz","_dist","_posxGun","_posxTarget","_posyGun","_posyTarget","_poszGun","_poszTarget"];
	diag_log Format["XfFireArtilleryPiece(): %1 (%2)",_this, diag_ticktime];
	_gun = _this select 0;
	_target = _this select 1;
	_rounds = _this select 2;
	_delay = _this select 3;
	
	// keep gun pointed at target
	_gun setCombatMode "BLUE";
	_gun disableAI "move";
	_gun disableAI "target";
	_gun disableAI "autotarget";
	_gun disableAI "anim";
	
	_newTarget = objNull;
	if (typename _target == typename objNull) then {
		_newTarget = "Land_HelipadEmpty_F" createVehicle (getPos _target);
	} else {
		_newTarget = "Land_HelipadEmpty_F" createVehicle _target;
	};
	
	_posxGun = ((getPosASL _gun) select 0);
	_posxTarget = ((getPosASL _newTarget) select 0);
	_posyGun = ((getPosASL _gun) select 1);
	_posyTarget = ((getPosASL _newTarget) select 1);
	_poszGun = ((getPosASL _gun) select 2);
	_poszTarget = ((getPosASL _newTarget) select 2);

	_tposx = _posxTarget + ((_posxGun - _posxTarget)*(3/4));
	_tposy = _posyTarget + ((_posyGun - _posyTarget)*(3/4));

	_dist = _target Distance _gun;

	if ( _poszGun > _poszTarget ) then {
		_tposz = (getPosASL _newTarget select 2) + (_dist/3);
	}
	else {
		_tposz = (getPosASL _gun select 2) + (_dist/5);
	};

	// create virtual target (empty hidden helipad in the air)
	_newTarget setPosASL [_tposx,_tposy,_tposz];

	// gunner will look at hidden targets 'flying' in the air
	(gunner _gun) lookAt _newTarget;
	sleep _delay / 2;
	// create eventhandler to monitor if gun is fired. If so, delete the fired round and put type of ammo in global variable
	_gun addEventHandler ["fired",{deleteVehicle (nearestObject [_this select 0, _this select 4]);}];
	While {alive (gunner _gun) && _rounds > 0} do
	{
		diag_log Format["XfFireArtilleryPiece(): Fire %1 (%2)", diag_ticktime,_rounds];
		_gun fire (weapons _gun select 0);
		_gun setVehicleAmmo 1;
		sleep _delay;
		_rounds = _rounds - 1;
	};
	// removing auto created hidden virtual target and eventhandler
	deleteVehicle _newTarget;
	_gun removeAllEventHandlers "fired";  
	_gun setCombatMode "RED";
	_gun enableAI "move";
	_gun enableAI "target";
	_gun enableAI "autotarget";
	_gun enableAI "anim";
};

// [_type, _kind, _pos, _delay] spawn XfBomber;
XfBomber = {
	private ["_type","_kind","_pos","_delay","_trails", "_netshell","_typetrail","_typeshell","_shell"];
	diag_log Format["XfBomber(): %1 (%2)",_this, diag_ticktime];
	_type = _this select 0;
	_kind = _this select 1;
	_pos = _this select 2;
	_delay = _this select 3;
	_trails = nil;
	_netshell = nil;
	if (_kind == 1) then {
		_typetrail = format["ARTY_TRAILFX_%1",_type];
		_typeshell = format["ARTY_NETSHELL_%1",_type];
		if (isnil _typetrail) then { missionNameSpace setVariable [_typetrail, getText (configFile >> "CfgAmmo" >> _type >> "ARTY_TrailFX")];};
		if (isnil _typeshell) then { missionNameSpace setVariable [_typeshell, getText (configFile >> "CfgAmmo" >> _type >> "ARTY_TrailFX")];};
		_trails =  missionNameSpace getVariable _typetrail;
		_netshell =  missionNameSpace getVariable _typeshell;
	};
	sleep _delay;
	diag_log Format["XfBomber(): Explode  %1 (%2)",diag_ticktime, _type];
	_shell = createVehicle [_type, _pos, [], 0, "NONE"];
	_shell setVelocity [0,0,-150];
	if (_kind == 1) then {["d_arty_trail", [getPosASL _shell, _trails, _netshell]] call XNetCallEvent};
};

// [_target_pos, _kind, _cannons, _shooting_array, _side] spawn XfShootArti;
XfShootArti = {
	private ["_shooting_info","_angle","_center_x","_center_y","_height","_i","_max_shells","_number_shells","_half_shells","_min_delay","_max_delay","_rand_delay","_max_interval"
			 ,"_pos_enemy","_radius","_type","_wp_array","_x1","_xo","_y1","_kind","_artilleries","_arty","_target_pos","_distance","_fire_delay","_arty_delay","_bomber_delay"];
	if (!isServer) exitWith {};
	diag_log Format["XfShootArti(): %1 (%2)",_this, diag_ticktime];
	_pos_enemy = _this select 0;
	_kind = _this select 1;
	if (typename _kind == typename "") then {
		_kind = switch (toupper(_kind)) do {
			case "FLARE": { 3 };
			case "SMOKE": { 2 };
			case "DPCIM": { 0 };
			default { 1 }; // HE
		};
	};
	if (_kind > 3) then { _kind = floor(random(3)) + 1; };
	
	_artilleries = [];
	if (count _this > 2) then { _artilleries = _this select 2; };
	// Number of shells,  Minimum delay between shells, Max delay between shells, Dispersion, Max Pieces interval
	_shooting_info = [6,6,9,30,3];
	if (count _this > 3) then { if ((count (_this select 3)) > 0) then { _shooting_info = _this select 3; }; };
	_side = d_enemy_side;
	if (count _this > 4) then { if ((_this select 4) != "") then { _side = _this select 4; }; };
	if (count _artilleries > 0) then {
		_side = str(side (_artilleries select 0));
	};
	_side = switch (toupper(_side)) do {
		case "WEST":{"WEST"};
		case "EAST":{"EAST"};
		default {d_enemy_side; };
	};
	
	if (count _artilleries > 0) then {
		for [{_i=0},{_i < count _artilleries},{_i = _i + 1} ] do {
			_arty = _artilleries select _i;
			if (typename _arty == typename objNull) then {
				if (alive _arty && canFire _arty && alive gunner _arty) then {
					
				} else {
					diag_log Format["XfShootArti(): Not active %1",[_arty, typeof _arty, alive _arty, canFire _arty, alive gunner _arty]];
					_artilleries set [_i, "XxDeLxX"];
				};
			} else {
				diag_log Format["XfShootArti(): Not an object %1",[_arty]];
				_artilleries set [_i, "XxDeLxX"];
			};
		};
		_artilleries = _artilleries - ["XxDeLxX"];
		diag_log Format["XfShootArti(): Remaining Arties %1",_artilleries];
	};
	
	_max_shells = 6;
	_min_delay = 6;
	_max_delay = 9;
	_radius = 30;
	_max_interval = 3;
	if (typename _shooting_info == typename []) then {
		if (count _shooting_info > 0) then { _max_shells = _shooting_info select 0 };
		if (count _shooting_info > 1) then { _min_delay = _shooting_info select 1 };
		if (count _shooting_info > 2) then { _max_delay = _shooting_info select 2 };
		if (count _shooting_info > 3) then { _radius = _shooting_info select 3 };
		if (count _shooting_info > 4) then { _max_interval = _shooting_info select 4 };
	};
	
	_half_shells = floor((_max_shells / 2) max 1);
	_min_delay = _min_delay max 0;
	_max_delay = (_max_delay max _min_delay) max 2;
	_rand_delay = _max_delay - _min_delay;
	_max_interval = _max_interval max 1;
	_height = switch (_kind) do {case 0: {150};case 1: {150}; case 2: {1}; default {150}};
	_center_x = _pos_enemy select 0;
	_center_y = _pos_enemy select 1;

	diag_log Format["XfShootArti(): Shooting Info %1", [_half_shells, _min_delay, _max_delay, _max_interval, [_center_x, _center_y, _height]]];
	
	if (isnil "d_ArtyShellsWest") then {
		d_ArtyShellsWest = [
			"ARTY_Flare_Medium", //flare
			"ARTY_Sh_105_HE", // HE
			"ARTY_SmokeShellWhite", // Smoke
			"G_30mm_HE", // dpicm
			"ARTY_Sh_105_SADARM" // SADARM
		];
	};

	if (isnil "d_ArtyShellsEast") then {
		d_ArtyShellsEast = [
			"ARTY_Flare_Medium", //flare
			"ARTY_Sh_122_HE", // HE
			"ARTY_SmokeShellWhite", // Smoke
			"G_40mm_HE", // dpicm
			"ARTY_Sh_122_SADARM" // SADARM
		];
	};

	_type = if (_side == "EAST") then {
		switch (_kind) do {
			case 0: {d_ArtyShellsEast select 3};
			case 1: {d_ArtyShellsEast select 1};
			case 3: {d_ArtyShellsEast select 0};
			default {d_ArtyShellsEast select 2};
		}
	} else {
		switch (_kind) do {
			case 0: {d_ArtyShellsWest select 3};
			case 1: {d_ArtyShellsWest select 1};
			case 3: {d_ArtyShellsWest select 0};
			default {d_ArtyShellsWest select 2};
		}
	};

	// if (_kind in [0,1]) then {
		// _number_shells = _half_shells + (ceil random _half_shells);
	// } else {
		// _number_shells = 1;
	// };
	_number_shells = _half_shells + (ceil random _half_shells);
	_max_shells = _number_shells;
	
	if (count _artilleries > 0) then {
		_number_shells = (ceil (_number_shells / (count _artilleries))) max 1;
		_max_shells = _number_shells * (count _artilleries);
	};

	_wp_array = [];
	while {(count _wp_array) < _max_shells} do {
		_angle = floor random 360;
		_x1 = _center_x - ((random _radius) * sin _angle);
		_y1 = _center_y - ((random _radius) * cos _angle);
		_wp_array set [count _wp_array, [_x1, _y1, _height]];
		sleep 0.0153;
	};
	diag_log Format["XfShootArti(): Impacts: %1  Shells: %2",_wp_array, [_number_shells, _max_shells]];
	sleep 1.234 + (random 2);
	private ["_trails", "_netshell"];
	_trails = "";
	_netshell = "";
	_i = 0;
	while {_i < (_max_shells)} do {
		_fire_delay = _min_delay + (ceil random _rand_delay);
		if (count _artilleries > 0) then {
			_arty_delay = _fire_delay;
			{
				_arty = _x;
				_target_pos = _wp_array select _i;
				_distance = _arty distance _target_pos;
				diag_log Format["XfShootArti(): Impacts: %1",_target_pos];
				[_arty, _target_pos, 1, _arty_delay] spawn XfFireArtilleryPiece;
				// delay impact based on distance to target (no realistic timing)
				_bomber_delay = _arty_delay + 1 + (round (_distance/333));
				[_type, _kind, _target_pos, _bomber_delay] spawn XfBomber;
				_arty_delay = _arty_delay + random (_max_interval);
				_i = _i + 1;
			} foreach _artilleries;
		} else {
			_target_pos = _wp_array select _i;
			[_type, _kind, _target_pos, 0] spawn XfBomber;
			_i = _i + 1;
		};
		sleep 0.923 + _fire_delay;
	};
	_wp_array = nil;
};